package com.liangxiao.wifichat;

import android.net.wifi.*;
import android.content.*;
import android.os.*;
import android.util.*;
import android.widget.Toast;
import com.liangxiao.wifichat.model.BaseMessage;
import org.apache.http.client.utils.CloneUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.HashSet;
import java.util.Set;
import java.util.*;

public class WifiChatService {

    private static final String TAG = "WifiChatService";

    private final WifiApManager ap;
    private final WifiManager wifi;

    private int mState = STATE_NONE;
    private final Handler mHandler;
    private final Context mContext;
    private List<ScanResult> scanResult = new ArrayList<>();

    private boolean isServer = false;

    private final Set<ConnectThread> mConnectThreads = new HashSet<>();
    private final Set<ConnectedThread> mConnectedThreads = new HashSet<>();
    private ConnectedThread mConnectedThread;
    private AcceptThread mAcceptThread = null;

    public static final int DEFAULT_SOCKET_SERVER_PORT = 8181;
    public static final int DEFAULT_SOCKET_TIMEOUT = 5000;

    public static final int STATE_NONE = 0;
    public static final int STATE_LISTEN = 1;
    public static final int STATE_CONNECTING = 2;
    public static final int STATE_CONNECTED = 3;
    public static final int STATE_SCAN = 4;

    public static final int MESSAGE_STATE_CHANGE = 10;
    public static final int MESSAGE_SCAN_RESULTS_AVAILABLE = 11;
    public static final int MESSAGE_READ = 12;
    public static final int MESSAGE_WRITE = 13;
    public static final int MESSAGE_CONNECT_FAILED = 14;
    public static final int MESSAGE_CONNECTION_LOST = 15;
    public static final int MESSAGE_STOP = 16;
    public static final int MESSAGE_SCAN = 17;
    public static final int MESSAGE_START = 18;
    public static final int MESSAGE_CONNECTED = 19;

    private static WifiChatService mService;

    private WifiChatService(Context context, Handler handler) {
        mContext = context;
        ap = new WifiApManager(context);
        wifi = ap.getWifiManager();
        scanResult = wifi.getScanResults();
        mHandler = handler;
    }

    public static WifiChatService getInstance(Context context, Handler handler) {
        if (mService == null) {
            mService = new WifiChatService(context, handler);
        }
        return mService;
    }

    public WifiApManager getApManager() {
        return ap;
    }
    public WifiManager getWifiManager() {
        return wifi;
    }

    public List<ScanResult> getScanResult() {
        return scanResult;
    }

    private synchronized void setState(int state) {
        Log.d(TAG, "setState() " + mState + " -> " + state);
        mState = state;
        mHandler.obtainMessage(MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
    }

    public synchronized int getState() {
        return mState;
    }

    public boolean isServer() {
        return isServer;
    }

    public synchronized void start() {

        setState(STATE_LISTEN);
        isServer = true;
        //TODO 启动连接
        if (mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
        mAcceptThread = new AcceptThread();
        mAcceptThread.start();
        mHandler.sendEmptyMessage(MESSAGE_START);
    }

    /**
     * 启动扫描
     */
    public synchronized void scan() {
        isServer = false;
        log("正在扫描");
        mHandler.sendEmptyMessage(MESSAGE_SCAN);
        IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        WifiReceiver wifiReceiver = new WifiReceiver();
        mContext.registerReceiver(wifiReceiver, filter);
        wifi.startScan();
        setState(STATE_SCAN);
    }

    /**
     * 启动连接
     *
     * @param targetIp 目标IP
     */
    public synchronized void connect(String targetIp) {
        isServer = false;
        ConnectThread thread = new ConnectThread(targetIp);
        thread.start();

        setState(STATE_CONNECTING);
    }

    /**
     * 成功连接一个连接
     *
     * @param socket 当前连接的Socket
     */
    private void connected(Socket socket) {
        //TODO Socket已连接
        log("连接成功，远程地址为" + socket.getRemoteSocketAddress().toString());

        ConnectedThread thread = new ConnectedThread(socket);
        thread.start();
        mConnectedThreads.add(thread);

        mConnectedThread = thread;

        mHandler.obtainMessage(MESSAGE_CONNECTED, -1, -1, socket.getInetAddress().getHostAddress()).sendToTarget();

        setState(STATE_CONNECTED);

    }

    /**
     * 写数据
     *
     * @param out
     */
    public void write(byte[] out) {
        ConnectedThread r;
        synchronized (this) {
            if (mState != STATE_CONNECTED) {
                log("当前状态为未连接");
                return;
            }
            r = mConnectedThread;

        }
        if (r != null) {
            r.write(out);
        } else {
            mHandler.obtainMessage(MESSAGE_CONNECTION_LOST).sendToTarget();
        }
    }

    /**
     * 连接失败
     */
    private void connectionFailed() {

        //TODO 尝试连接失败
        mHandler.obtainMessage(MESSAGE_CONNECT_FAILED).sendToTarget();

		
    }

    /**
     * 连接断开
     */
    private void connectionLost() {

        //TODO 某个连接断开
        mHandler.obtainMessage(MESSAGE_CONNECTION_LOST).sendToTarget();

    }

    /**
     * 停止所有线程
     */
    public synchronized void stop() {

        if (mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
        if (mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
        setState(STATE_NONE);
    }

    /**
     * 接受其他设备的连接请求
     */
    private final class AcceptThread extends Thread {

        ServerSocket serverSocket = null;

        public AcceptThread() {
            try {
                serverSocket = new ServerSocket(DEFAULT_SOCKET_SERVER_PORT);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            super.run();
            Log.d(TAG, "begin accept message");
            setName("AcceptThread");
            Socket socket = null;
            while (mState != STATE_CONNECTED) {
                try {
                    //仅当连接成功或抛出异常时该方法才会返回
                    socket = serverSocket.accept();
					log("接受成功");
                } catch (IOException e) {
                    Log.e(TAG, "AcceptThread accept() failed", e);
                    break;
                }

                //接收到一个连接
                if (socket != null) {
                    synchronized (this) {
                        switch (mState) {
                            case STATE_LISTEN:
                            case STATE_CONNECTING:
                                connected(socket);
                                break;
                            case STATE_NONE:
                            case STATE_CONNECTED:
                                try {
                                    Log.d(TAG,"关闭不需要的Socket");
									socket.close();
								}catch (IOException e){
									Log.e(TAG,"关闭不需要的Socket",e);
								}
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
            Log.d(TAG, "AcceptedThread结束");
        }

        public void cancel() {
            Log.d(TAG, "取消AcceptThread");
            try {
                serverSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "AcceptedThread close()失败", e);
            }

        }
    }

    /**
     * 向目标设备发起连接请求
     */
    private final class ConnectThread extends Thread {

        private final Socket mSocket;
        private final String targetIp;

        public ConnectThread(String targetIp) {
            this.targetIp = targetIp;
            mSocket = new Socket();
        }

        @Override
        public void run() {
            Log.d(TAG, "开始向目标设备发起请求，目标IP：" + targetIp);
            setName("ConnectThread");

            SocketAddress address = new InetSocketAddress(targetIp, DEFAULT_SOCKET_SERVER_PORT);
            try {
                mSocket.connect(address, DEFAULT_SOCKET_TIMEOUT);
            } catch (IOException e) {
                try {
                    mSocket.close();
                } catch (IOException e1) {
                    Log.e(TAG, "无法关闭已连接失败的Socket", e);
                }
                connectionFailed();
                return;
            }
            //关闭连接进程
          /*  synchronized (this) {
                //mConnectThreads.remove(this);
            }*/

            connected(mSocket);
        }
    }


    /**
     * 已连接其他设备的情况下，接受其他设备发来的消息
     */
    private final class ConnectedThread extends Thread {

        private final Socket mSocket;
        private final InputStream mInStream;
        private final OutputStream mOutStream;
        private final String ip;

        public ConnectedThread(Socket socket) {

            mSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            ip = mSocket.getInetAddress().getHostAddress();

            // 获取Socket的输入输出流
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mInStream = tmpIn;
            mOutStream = tmpOut;
        }

        @Override
        public void run() {
            Log.d(TAG, "启动ConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;
            //保持监听
            while (true) {
                try {
                    bytes = mInStream.read(buffer);
					//if(bytes <=0) continue;
                    //Toast.makeText(mContext,new String(buffer),Toast.LENGTH_SHORT).show();
                    BaseMessage message = new BaseMessage();
                    message.setName(ip);
                    message.setContent(new String(buffer));

					log("接受消息"+new String(buffer));

                    mHandler.obtainMessage(MESSAGE_READ, bytes, -1, message).sendToTarget();
                } catch (IOException e) {
                    Log.e(TAG, "连接断开", e);
                    connectionLost();
                    //TODO 需要重启监听
                    break;
                }
            }

        }

        /**
         * 写数据
         *
         * @param buffer 需要传送的数据
         */
        public void write(byte[] buffer) {
            try {
                mOutStream.write(buffer);
                BaseMessage msg = new BaseMessage();
                msg.setName("我");
                msg.setContent(new String(buffer));
				log("send msg");
                mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, msg).sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

        /**
         * 取消ConnectedThread进程
         */
        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() 错误", e);
            }
        }
    }


    private final class WifiReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context p1, Intent p2) {
            // TODO: Implement this method
            //scanResult.clear();
            //scanResult = null;
            scanResult = wifi.getScanResults();
            mHandler.obtainMessage(MESSAGE_SCAN_RESULTS_AVAILABLE).sendToTarget();
            mContext.unregisterReceiver(this);
        }


    }

    private static void log(String log) {
        Log.d(TAG, log);
    }
}
